/*
 * Copyright 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package be.obia.moo.dovebird;

import java.io.IOException;
import java.util.Vector;

import be.obia.moo.dovebird.R;

import android.app.ActionBar;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity implements TCPListener {
	Thread clientThread;
	TCPClient client;

    boolean AutoConnect;
    boolean EnableANSIColors;
    boolean DisplayAboutTab;
    Integer MaximumTextBuffer;
    String StartupAsciiArt;
    String Hostname;
    Integer Port;
    Integer FontSize;
	String MOOName;
    
    public String versionName;
    public Integer versionCode;
    public String RenderMode;
    
    public ActionBar bar;

    private void getPrefs() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
        	DisplayAboutTab = prefs.getBoolean("abouttab", true);
            StartupAsciiArt = prefs.getString("startup_ascii_art", "chunky");
        	AutoConnect = prefs.getBoolean("autoconnect", false);
            MOOName = prefs.getString("mooname", "Your MOO");
            Hostname = prefs.getString("hostname", "");
            Port = Integer.valueOf(prefs.getString("port", "1111"));
            EnableANSIColors = prefs.getBoolean("ansicolor", true);
            FontSize = Integer.valueOf(prefs.getString("fontsize", "10"));
            MaximumTextBuffer = Integer.valueOf(prefs.getString("textbuffersize", "10000"));
    }
    
	public void onStart(){
			super.onStart();
			getPrefs();
	        TextView t = (TextView)findViewById(R.id.textView1);
	        t.setTextSize(FontSize);	
			
			if(client != null && client.socket != null && client.socket.isConnected())
				return;
			
	        t.setText("");
	        EditText et = (EditText)findViewById(R.id.edittext);
	        et.setOnEditorActionListener(editTextListener);
	        
	        if(AutoConnect) {
	        	connectToMOO();
			} else if(StartupAsciiArt.equals("chunky")) {
				Spannable logo1 = new SpannableString("    _____                    ______ __          __ \n");
				Spannable logo2 = new SpannableString("   |     \\.-----.--.--.-----|   __ \\__|.----.--|  |\n");
				Spannable logo3 = new SpannableString("   |  --  |  _  |  |  |  -__|   __ <  ||   _|  _  |\n");
				Spannable logo4 = new SpannableString("   |_____/|_____|\\___/|_____|______/__||__| |_____|\n");
				
				Integer s = 3; // This is the amount of additional spaces to the left of the logo.
		        logo1.setSpan(new ForegroundColorSpan(Color.WHITE), 0 + s, 25 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo1.setSpan(new ForegroundColorSpan(Color.GREEN), 25 + s, 48 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo2.setSpan(new ForegroundColorSpan(Color.WHITE), 0 + s, 25 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo2.setSpan(new ForegroundColorSpan(Color.GREEN), 25 + s, 48 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo3.setSpan(new ForegroundColorSpan(Color.WHITE), 0 + s, 25 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo3.setSpan(new ForegroundColorSpan(Color.GREEN), 25 + s, 48 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo4.setSpan(new ForegroundColorSpan(Color.WHITE), 0 + s, 25 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo4.setSpan(new ForegroundColorSpan(Color.GREEN), 25 + s, 48 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
     	        t.setText(TextUtils.concat(logo1, logo2, logo3, logo4));
			} else if(StartupAsciiArt.equals("figlet")) {
				Spannable logo1 = new SpannableString("          ___              ___ _        _ \n");
				Spannable logo2 = new SpannableString("         |   \\ _____ _____| _ |_)_ _ __| |\n");
				Spannable logo3 = new SpannableString("         | |) / _ \\ V / -_) _ \\ | '_/ _` |\n");
				Spannable logo4 = new SpannableString("         |___/\\___/\\_/\\___|___/_|_| \\__,_|\n");
				
				Integer s = 8; // This is the amount of additional spaces to the left of the logo.
		        logo1.setSpan(new ForegroundColorSpan(Color.WHITE), 0 + s, 18 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo1.setSpan(new ForegroundColorSpan(Color.GREEN), 18 + s, 34 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo2.setSpan(new ForegroundColorSpan(Color.WHITE), 0 + s, 18 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo2.setSpan(new ForegroundColorSpan(Color.GREEN), 18 + s, 34 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo3.setSpan(new ForegroundColorSpan(Color.WHITE), 0 + s, 19 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo3.setSpan(new ForegroundColorSpan(Color.GREEN), 19 + s, 34 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo4.setSpan(new ForegroundColorSpan(Color.WHITE), 0 + s, 19 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		        logo4.setSpan(new ForegroundColorSpan(Color.GREEN), 19 + s, 34 + s, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
     	        t.setText(TextUtils.concat(logo1, logo2, logo3, logo4));
	        }
	        String versionMessage = "";
	        versionMessage += "\n                DoveBird - " + versionName + "\n";
	        versionMessage += "     created by Peter Corcoran and Stephen Gigante\n\n";
			Spannable versionSpan = new SpannableString(versionMessage);
	        versionSpan.setSpan(new ForegroundColorSpan(Color.WHITE), 0, versionMessage.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
	        t.append(versionSpan);
	}
	
	TextView.OnEditorActionListener editTextListener = new TextView.OnEditorActionListener(){
		public boolean onEditorAction(TextView object, int actionId, KeyEvent event) {
			   if(actionId == EditorInfo.IME_ACTION_DONE)
			   {
				   client.sendData(object.getText().toString());
				   object.setText("");
			   }
			   return true;
			}
	};

	
    public void onCreate(Bundle savedInstanceState) {
        RenderMode = this.getString(R.string.render_mode);
    	
    	try {
			versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
    		versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
		} catch (NameNotFoundException e) {
			versionName = "0.0.0-unknown";
			versionCode = 0;
		}
    	
        PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
        
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        if(RenderMode.equals("tablet")) {
            bar = getActionBar();
            bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
            if(DisplayAboutTab)
            	bar.addTab(bar.newTab().setText(RenderMode + "-" + versionName).setTabListener(new DBTabListener(this, "about")));
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.main, menu);

        // Calling super after populating the menu is necessary here to ensure that the
        // action bar helpers have a chance to handle this event.
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                Toast.makeText(this, "DoveBird " + versionName + " [by Peter Corcoran and Stephen Gigante]", Toast.LENGTH_SHORT).show();
                break;
            case R.id.menu_connect:
                Toast.makeText(this, "Connecting...", Toast.LENGTH_SHORT).show();
                connectToMOO();
                getActionBarHelper().setRefreshActionItemState(true);
                getWindow().getDecorView().postDelayed(
                        new Runnable() {
                            public void run() {
                                getActionBarHelper().setRefreshActionItemState(false);
                            }
                        }, 1000);
                break;
            case R.id.menu_settings:
                Intent launchPreferencesIntent = new Intent().setClass(this, Preferences.class);
                startActivity(launchPreferencesIntent);
                break;
        }
        return super.onOptionsItemSelected(item);
    }
    
    public boolean connectToMOO(){
    	if(client != null)
    	{
    		client.keepConnected = false;
    		if(client.socket != null && client.socket.isConnected())
				try {
					client.socket.close();
				} catch (IOException e) { }
    	}
    	if(clientThread != null && clientThread.isAlive())
    		clientThread.stop();

        TextView t = (TextView)findViewById(R.id.textView1);
    	t.setText("");
        
    	if(RenderMode.equals("tablet")) {
    		bar.removeAllTabs();
            if(DisplayAboutTab)
            {
            	bar.addTab(bar.newTab().setText(RenderMode + "-" + versionName).setTabListener(new DBTabListener(this, "about")));
    			bar.addTab(bar.newTab().setText(MOOName).setTabListener(new DBTabListener(this, "moo_window")));
    			bar.setSelectedNavigationItem(1);
            } else {
        		bar.addTab(bar.newTab().setText(MOOName).setTabListener(new DBTabListener(this, "moo_window")));
            }
    	}
    	client = new TCPClient(Hostname, Port, this);
    	clientThread = new Thread(client);
    	clientThread.start();
        return true;
    }
    
	public void lineReceived(final TCPLine line) {
		if(line.Line.indexOf("#$#") == 0) {
			client.MCP.Handle(line);
			return;
		} else if(line.Line.equals("*** Connected ***")) {
			// This is cheap and nasty, but got me identifing the client as doveBird!
			// Awaiting full MCP implimentation.
		}
	    final Vector<ANSIspan> spanParts = new Vector<ANSIspan>(); 
	    String finalLine = "";
		boolean inAnsiTag = false;
		boolean isBold = false;
		String currentTag = "";
		Integer difference = 0;
	    Vector<ANSIspan> openParts = new Vector<ANSIspan>(); 
		for(int i = 0; i < line.Line.length(); i++){
			char letter = line.Line.charAt(i);
			if(letter == 0x1B) {
				inAnsiTag = true;
			} else if(inAnsiTag && letter == 'm') {
				// end of ansi tag!
    		    Vector<String> parts = new Vector<String>(); 
    		    Integer extra = 2;
				if(currentTag.contains(";")) {
				  Integer where = currentTag.indexOf(";");
				  String p1 = currentTag.substring(1, where);
				  String p2 = currentTag.substring(where + 1);
				  parts.add(p1);
				  parts.add(p2);
				  extra = 3;
				} else {
				  String p1 = currentTag.substring(1);
				  parts.add(p1);
				}
				difference += currentTag.length() + extra;
				currentTag = "";

    	    	for(int x = 0, size = parts.size(); x < size; x++) {
    	    		String p = parts.get(x);
    	    		Integer code = Integer.valueOf(p);
    	    		switch(code) {
    	    			case 1:
    	    				ANSIspan span1 = new ANSIspan();
    	    				span1.Foreground = Color.WHITE;
    	    				span1.Start = 1 + i - difference;
    	    				openParts.add(span1);
    	    				isBold = true;
    	    				break;
    	    			case 30:
    	    			case 39:
    	    				ANSIspan span30 = new ANSIspan();
    	    				span30.Foreground = isBold ? Color.LTGRAY : Color.WHITE;
    	    				span30.Start = 1 + i - difference;
    	    				openParts.add(span30);
    	    				break;
    	    			case 31:
    	    				ANSIspan span31 = new ANSIspan();
    	    				span31.Foreground = isBold ? Color.rgb(255, 0, 0) : Color.rgb(127, 0, 0);
    	    				span31.Start = 1 + i - difference;
    	    				openParts.add(span31);
    	    				break;
    	    			case 32:
    	    				ANSIspan span32 = new ANSIspan();
    	    				span32.Foreground = isBold ? Color.rgb(0, 255, 0) : Color.rgb(0, 127, 0);
    	    				span32.Start = 1 + i - difference;
    	    				openParts.add(span32);
    	    				break;
    	    			case 33:
    	    				ANSIspan span33 = new ANSIspan();
    	    				span33.Foreground = isBold ? Color.rgb(255, 255, 0) : Color.rgb(127, 127, 0);
    	    				span33.Start = 1 + i - difference;
    	    				openParts.add(span33);
    	    				break;
    	    			case 34:
    	    				ANSIspan span34 = new ANSIspan();
    	    				span34.Foreground = isBold ? Color.rgb(0, 0, 255) : Color.rgb(0, 0, 127);
    	    				span34.Start = 1 + i - difference;
    	    				openParts.add(span34);
    	    				break;
    	    			case 35:
    	    				ANSIspan span35 = new ANSIspan();
    	    				span35.Foreground = isBold ? Color.rgb(128, 0, 128) : Color.rgb(64, 0, 64);
    	    				span35.Start = 1 + i - difference;
    	    				openParts.add(span35);
    	    				break;
    	    			case 36:
    	    				ANSIspan span36 = new ANSIspan();
    	    				span36.Foreground = isBold ? Color.rgb(0, 255, 255) : Color.rgb(0, 127, 127);
    	    				span36.Start = 1 + i - difference;
    	    				openParts.add(span36);
    	    				break;
    	    			case 37:
    	    				ANSIspan span37 = new ANSIspan();
    	    				span37.Foreground = isBold ? Color.LTGRAY : Color.WHITE;
    	    				span37.Start = 1 + i - difference;
    	    				openParts.add(span37);
    	    				break;
    	    			case 0:
    	    				isBold = false;
    	    				for(int y = 0, size2 = openParts.size(); y < size2; y++)
    	    				{
    	    					ANSIspan part = openParts.get(y);
    	    					part.Start = part.Start < 0 ? 0 : part.Start;
    	    				    part.End = 1 + i - difference;
    	    					spanParts.add(part);
    	    				}
    	    				openParts.clear();
    	    				break;
    	    		}
    	    	}
				inAnsiTag = false;
			} else if(inAnsiTag) {
				currentTag += letter;
			} else {
				finalLine += letter;
			}
		}
		for(int y = 0, size2 = openParts.size(); y < size2; y++)
		{
			ANSIspan part = openParts.get(y);
			part.Start = part.Start < 0 ? 0 : part.Start;
		    part.End = line.Line.length() - difference;
			spanParts.add(part);
		}
		final String realFinalLine = finalLine;
    	runOnUiThread(new Runnable() {
    		public void run() {
    			Spannable lineSpan = new SpannableString(realFinalLine + "\n");
	    		lineSpan.setSpan(new ForegroundColorSpan(Color.LTGRAY), 0, lineSpan.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    			if(EnableANSIColors)
    			{
	    	    	for(int i=0, size = spanParts.size(); i < size; i++) {
	    	    		ANSIspan span = spanParts.get(i);
	    	    		lineSpan.setSpan(new ForegroundColorSpan(span.Foreground), span.Start, span.End, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
	    	    		lineSpan.setSpan(new BackgroundColorSpan(span.Background), span.Start, span.End, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
	    	    	}
    			}

    			TextView t = (TextView)findViewById(R.id.textView1);
    			CharSequence oldLines = t.getText();
    			
    			if(oldLines.length() > MaximumTextBuffer)
    				t.setText("");
    			
    			t.append(lineSpan);

    			final ScrollView sv = (ScrollView)findViewById(R.id.scrollView1);
    		    sv.post(new Runnable() { 
    		        public void run() { 
    		            sv.smoothScrollBy(0, 60); 
    		        } 
    		    }); 
    		}
    	});
	}
}
